
#include "libClient.h"

#include "dbusCommon.h"


#include <gio/gio.h>       /** GIO for dbus*/
#include <glib-2.0/glib.h> /** GLIB for main loop*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>




static GMainLoop *pLoop = NULL;

/* 服务端影子对象 */
static RTplayGdbusExample *pProxy = NULL;

/* 回调处理函数(业务注册) */
static S_SIGNAL_CALLBACK g_signal_callback;
static S_METHOD_CALLBACK g_method_callback;

static gboolean My_Signal_1_Handler(RTplayGdbusExample *object, const gchar *arg, gpointer userdata);

static gboolean My_Signal_2_Handler(RTplayGdbusExample *object, GVariant *arg, gpointer userdata);

static void MethodCallback_1(GObject *source_object, GAsyncResult *res, gpointer userdata);

static void MethodCallback_2(GObject *source_object, GAsyncResult *res, gpointer user_data);

static int thread_create(void);

static void *run(void *arg);




/* 接收服务信号1 */
static gboolean My_Signal_1_Handler(RTplayGdbusExample *object, const gchar *arg, gpointer userdata)
{
    if (NULL != g_signal_callback.callback1)
        g_signal_callback.callback1(arg);
    return TRUE;
}



/* 接收服务信号2 */
static gboolean My_Signal_2_Handler(RTplayGdbusExample *object, GVariant *arg, gpointer userdata)
{
    /** get the value from GVariant */
    gint int_arg = 0;
    gchar *char_arg = NULL;

    g_variant_get(arg, "(is)", &int_arg, &char_arg);

    if (NULL != g_signal_callback.callback2)
        g_signal_callback.callback2(int_arg, char_arg);
    g_free(char_arg);

    return TRUE;
}




/* 注册信号回调 */
void registerSignalCallback(S_SIGNAL_CALLBACK *callback)
{
    if (NULL != callback)
        memcpy(&g_signal_callback, callback, sizeof(S_SIGNAL_CALLBACK));
	else
        g_print("registerSignalCallback: parameter point is NULL\n");
}




/* 注册方法回调 */
void registerMethodCallback(S_METHOD_CALLBACK *callback)
{
    if (NULL != callback)
        memcpy(&g_method_callback, callback, sizeof(S_SIGNAL_CALLBACK));
	else
        g_print("registerMethodCallback: parameter point is NULL\n");
}




/* 方法回调1 */
static void MethodCallback_1(GObject *source_object, GAsyncResult *res, gpointer userdata)
{
    g_print("client MethodCallback_1 call.\n");

    gchar *out_arg = NULL;
    GError *pError = NULL;

    rtplay_gdbus_example_call_my_method1_finish(pProxy, &out_arg, res, &pError);

    if (NULL == pError)
	{
        if (NULL != g_method_callback.callback1)
		{
            g_method_callback.callback1(out_arg, pError);
            g_free(out_arg);
        }
    }
	else
	{
        g_error_free(pError);
    }
}




/* 异步方法1 */
void myMethodAsync_1(const char *in_arg)
{
    g_print("client myMethodAsync_1 call, in_arg = %s.\n", in_arg);
    rtplay_gdbus_example_call_my_method1(pProxy, in_arg, NULL, MethodCallback_1, NULL);
}




/* 同步方法1 */
void myMethod_1(const gchar *in_arg, gchar **out_arg, GError **pError)
{
    rtplay_gdbus_example_call_my_method1_sync(pProxy, in_arg, out_arg, NULL, pError);

    if (*pError == NULL)
	{
        g_print("client myMethod_1 call, in_arg = %s out_arg = %s.\n", in_arg, *out_arg);
        g_free(*out_arg);
    }
	else
	{
        g_print("client myMethod_1: Failed to call method. Reason: %s.\n", (*pError)->message);
        g_error_free(*pError);
    }
}




/* 方法回调2 */
static void MethodCallback_2(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
    g_print("client MethodCallback_2 call.\n");

    GVariant *out_arg = NULL;
    GError *pError = NULL;
    gchar *out_arg1 = NULL;
    gint out_arg2 = 0;

    rtplay_gdbus_example_call_my_method2_finish(pProxy, &out_arg, res, &pError);
    if (NULL == pError)
	{
        g_variant_get(out_arg, "(si)", &out_arg1, &out_arg2);
        if (NULL != g_method_callback.callback2)
		{
            g_method_callback.callback2(out_arg1, out_arg2, pError);
            g_free(out_arg1);
        }
    }
	else
	{
        g_error_free(pError);
    }
}



/* 异步方法2 */
void myMethodAsync_2(const gint in_arg1, const gint in_arg2)
{
    g_print("client myMethodAsync_2 call, in_arg1 = %d, in_arg2 = %d.\n", in_arg1, in_arg2);

    GVariant *in_arg = g_variant_new("(ii)", in_arg1, in_arg2);
    rtplay_gdbus_example_call_my_method2(pProxy, in_arg, NULL, MethodCallback_2, NULL);
}




/* 同步方法2 */
void myMethod_2(const gint in_arg1, const gint in_arg2, gchar **out_arg1, gint *out_arg2, GError **pError)
{
    GVariant *in_arg = NULL;
    GVariant *out_arg = NULL;

    in_arg = g_variant_new("(ii)", in_arg1, in_arg2);
    rtplay_gdbus_example_call_my_method2_sync(pProxy, in_arg, &out_arg, NULL, pError);
	
    if (NULL == *pError)
	{
        g_variant_get(out_arg, "(si)", out_arg1, out_arg2);
        g_print("client myMethod_2 call, in_arg1 = %d, in_arg2 = %d, out_arg1 = %s, out_arg2 = %d.\n", 
			in_arg1, in_arg2, *out_arg1, *out_arg2
		);
        g_free(*pError);
    }
	else
	{
        g_print("client myMethod_2: Failed to call method. Reason: %s.\n", 
			(*pError)->message
		);
        g_error_free(*pError);
    }
}




void *run(void *arg)
{
    g_print("run call in the client.\n");
    g_main_loop_run(pLoop);
    return ((void *)0);
}




int thread_create(void)
{
    int err;
    pthread_t thr;

    err = pthread_create(&thr, NULL, run, NULL);

    if (0 != err)
	{
        g_print("Can't create thread: %s\n", strerror(err));
    }
	else
	{
        g_print("New thread created: %s\n", strerror(err));
    }

    return err;
}




/* !!! 这里主要是连接服务端，取得服务端的影子对象
	其他方法都是通过影子对象和服务端通讯的 */
bool InitDBusCommunication(void)
{
    bool bRet = TRUE;
    GError *_pError = NULL;
    GDBusConnection *_pGdbus_connection = NULL;

    g_print("InitDBusCommunication: Client started.\n");

    pLoop = g_main_loop_new(NULL, FALSE);

    do {
        bRet = TRUE;

        // 同步连接并建立D-Bus客户端连接，以与由地址指定的端点交换D-Bus消息。
        _pGdbus_connection = g_dbus_connection_new_for_address_sync(
            "unix:abstract=gdbus_server",
			G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
			NULL,
			NULL,
			&_pError
		);

        if (_pError)
		{
            g_print("gdbus connection fail in InitDBusCommunication,%s\n", _pError->message);
            g_error_free(_pError);
            _pError = NULL;
            bRet = FALSE;
        }
		else
		{
            pProxy = rtplay_gdbus_example_proxy_new_sync(
				_pGdbus_connection,
				G_DBUS_PROXY_FLAGS_NONE,
				NULL,
				RTPLAY_GDBUS_EXAMPLE_OBJECT_PATH,
				NULL,
				&_pError
			);

            if (pProxy == NULL)
			{
                g_print("snd_mgr_proxy_new_sync fail in thread_entry,%s\n", _pError->message);
                g_error_free(_pError);
                _pError = NULL;
                bRet = FALSE;
            }

			/* 监听信号 */
            g_signal_connect(pProxy, "my-signal1", G_CALLBACK(My_Signal_1_Handler), NULL);
            g_signal_connect(pProxy, "my-signal2", G_CALLBACK(My_Signal_2_Handler), NULL);
        }
        sleep(1);
    } while (FALSE == bRet);

    thread_create();
    return bRet;
}





bool DeInitDBusCommunication(void)
{
    bool bRet = FALSE;

    if (0 != pLoop)
	{
        g_main_loop_quit(pLoop);
        g_main_loop_unref(pLoop);
        bRet = TRUE;
    }

    return bRet;
}
